package configuration;


import java.io.File;
import java.util.ArrayList;
import java.util.Hashtable;

import configuration.options.AdjustmentOption;
import configuration.options.CompoundOption;
import configuration.options.DummyAdjustmentOption;
import configuration.options.PrecisionFitter;
import configuration.options.QXtractRetrain;
import configuration.options.WordFrequencyFitter;
import database.mediator.MediatorInterface;
import database.mediator.MySQLMediator;
import distributedRE.model.DataBase;
import distributedRE.model.Query;
import distributedRE.model.Relation;
import documentsampler.DocumentSampler;
import documentsampler.PoolSampler;
import estimators.numberoOfDocuments.DocumentEstimator;
import estimators.numberoOfDocuments.GlossEstimator;
import informationExtractionSystem.InformationExtractor;
import informationExtractionSystem.OpenCalaisExtractor;
import policy.stop.StopPolicy;
import policy.stop.TTuplesExtracted;
import querydatabaseselection.selector.FirstKDescendingOrder;
import querydatabaseselection.selector.QueryDatabaseSelector;
import querydatabaseselection.selector.UpToMDatabases;
import rankingGenerator.MeanUsefulValue;
import rankingGenerator.RankingGenerator;
import rankingGenerator.UsefulDocumentsSelector;
import searchEngine.LuceneSearchEngine;
import searchEngine.SearchEngine;
import statistics.generator.StatisticsGenerator;
import statistics.generator.TimeStatisticsPrinter;
import utils.FileHandlerUtils;
import workload.impl.condition.TuplesCondition;
import workload.impl.condition.UsefulCondition;
import workload.impl.condition.WorkLoadCondition;

public class ConfigurationLoader {

	private static final String ATTRIBUTE_SEPARATOR_VALUE = "@";
	
	private static final String QUERY_DATABASE_SELECTOR = "QUERY_DATA_BASE_SELECTOR";
	
	private static final String SEARCH_ENGINE = "SEARCH_ENGINE";
	
	private static final String INFORMATION_EXTRACTOR = "INFORMATION_EXTRACTOR";
	
	private static final String STOP_POLICY = "STOP_POLICY";
	
	private static final String STATISTICS_GENERATOR = "STATISTICS_GENERATOR";
	
	private static final String ADJUSTMENT_OPTION = "ADJUSTMENT_OPTION";
	
	private static final String RANKING_GENERATOR = "RANKING_GENERATOR";
	
	private static final String MEDIATOR_INTERFACE = "MEDIATOR_INTERFACE";
	
	private static final String EXPERIMENT_ID = "EXPERIMENT_ID";
	
	private static final String ENVIRONMENT_CONFIGURATION = "ENVIRONMENT_CONFIGURATION";
	
	private static final String NUMBER_OF_DOCUMENTS_CALCULATOR = "NUMBER_OF_DOCUMENTS_CALCULATOR";
	
	private static final String STOP_WORDS_FILE = "STOP_WORDS_FILE";

	private static final String RELATION = "RELATION";

	private static final String DATABASES = "DATABASES";

	private static final String QUERIES = "QUERIES";
	
	private static final String USEFUL_CONDITION = "USEFUL_CONDITION";
	
	private static QueryDatabaseSelector qdbs = null;
	
	private static SearchEngine se = null;

	private static InformationExtractor ie = null;

	private static StopPolicy sp = null;

	private static StatisticsGenerator sg = null;

	private static AdjustmentOption ao = null;

	private static RankingGenerator rg = null;

	private static MediatorInterface mi = null;

	private static ArrayList<DataBase> databases = null;

	private static ArrayList<Query> queries = null;

	private static Integer e_id = null;

	private static String env = null;
	
	private static DocumentEstimator dEst = null;
	
	private static UsefulCondition usefulCondition = null;
	
	private Hashtable<String, String> attrs;

	private String sw = null;

	private Relation r;

	public void load(String file) {
		
		attrs = new Hashtable<String, String>();
		
		ArrayList<String> lines = FileHandlerUtils.getAllResourceNames(new File(file));
		
		for (String line : lines) {
			
			String[] av = line.split(ATTRIBUTE_SEPARATOR_VALUE);
			
			attrs.put(av[1], av[0]);
			
		}
		
		
	}

	public QueryDatabaseSelector getQueryDatabaseSelector() {
		
		if (qdbs == null){
			
			String value = attrs.get(QUERY_DATABASE_SELECTOR);
			
			if (value.startsWith("FirstKDescendingOrder")){
				
				ArrayList<String> params = extractParameters(value);
				
				String k = params.get(0);
				qdbs = new FirstKDescendingOrder(new Integer(k).intValue());
			}
			
			if (value.startsWith("UpToMDatabases")){
				
				ArrayList<String> params = extractParameters(value);
				
				String k = params.get(0);
				qdbs = new UpToMDatabases(new Long(k).intValue());
			}
			
		}
		
		return qdbs;
	}
	
	public AdjustmentOption getAdjustmentOption() {
		
		if (ao == null){
			
			String value = attrs.get(ADJUSTMENT_OPTION);
			
			ao = generateAdjustmentOption(value);
			
		}
		
		return ao;
		
	}

	private AdjustmentOption generateAdjustmentOption(String value) {
		
		if (value.startsWith("CompoundOption")){
			
			ArrayList<String> as = extractParameters(value);
			
			return new CompoundOption(generateAdjustmentOption(as.get(0)), generateAdjustmentOption(as.get(1)),Integer.parseInt(as.get(2)));
			
		} else if (value.startsWith("PrecisionFitter")){
			ArrayList<String> as = extractParameters(value);
			
			return new PrecisionFitter(getInformationExtractor(),Integer.parseInt(as.get(0)), Double.parseDouble(as.get(1)));
		} else if (value.startsWith("QXtractRetrain")){
			
			
			ArrayList<String> as = extractParameters(value);
	
			return new QXtractRetrain(Integer.parseInt(as.get(0)),Integer.parseInt(as.get(1)),Double.parseDouble(as.get(2)),
					Integer.parseInt(as.get(3)),Long.parseLong(as.get(4)),Boolean.parseBoolean(as.get(5)),Boolean.parseBoolean(as.get(6)),getDocumentSampler(as.get(7)),getStopWordsFile(),new String(getExperimentId() + "-aux.txt"),RELATION,getExtractionTable());
		
		} else if (value.startsWith("WordFrequencyFitter")){
			
			ArrayList<String> as = extractParameters(value);
			
			return new WordFrequencyFitter(Integer.parseInt(as.get(0)));
		}
		
		return new DummyAdjustmentOption(1);
	}

	private DocumentSampler getDocumentSampler(String string) {
		if (string.startsWith("PoolSampler")){
			ArrayList<String> params = extractParameters(string);
			return new PoolSampler(Long.parseLong(params.get(0)));
		}
			
		return null;
	}

	private ArrayList<String> extractParameters(String value) {
		
		ArrayList<String> actualParameters = new ArrayList<String>();
		
		String params = value.substring(value.indexOf('(')+1, value.lastIndexOf(')'));
		
		ArrayList<Integer> arrI = new ArrayList<Integer>();
		
		int parenthesis = 0;
		
		for (int i = 0; i < params.length(); i++) {
			
			if (params.charAt(i) == '('){
				parenthesis++;
			}else if (params.charAt(i) == ')'){
				parenthesis--;
			}else if (params.charAt(i) == ',') {
				if (parenthesis==0)
					arrI.add(new Integer(i));
			}
		}
		
		int index = 0;
		
		for (Integer integer : arrI) {
			actualParameters.add(params.substring(index, integer.intValue()));
			index = integer.intValue()+1; //skip the comma
		}
		
		actualParameters.add(params.substring(index,params.length()));
		
		return actualParameters;
	}

	public SearchEngine getSearchEngine() {
		
		if (se == null){
			
			String value = attrs.get(SEARCH_ENGINE);
			
			if (value.startsWith("LuceneSearchEngine")){
				
				ArrayList<DataBase> databases = getDatabases();
				
				for (DataBase dataBase : databases) {
					se = new LuceneSearchEngine(dataBase,getStopWordsFile());
				}
				
			}
		}
		
		return se;
	}

	private String getStopWordsFile() {
		
		if (sw==null){
			
			sw = attrs.get(STOP_WORDS_FILE);
			
		}
		
		return sw;
		
	}

	public InformationExtractor getInformationExtractor() {

		if (ie == null){
			
			String value = attrs.get(INFORMATION_EXTRACTOR);
			
			if (value.startsWith("OpenCalaisExtractor")){
				
				ArrayList<String> params = extractParameters(value);
				
				ie = new OpenCalaisExtractor(params.get(0),getStorageMediator(),getRelation(),getUsefulCondition(),new String(getExperimentId()+"-auxExtract.txt"),getExtractionTable());
			}
		}
		
		return ie;
	}

	private String getExtractionTable() {
		// TODO Auto-generated method stub
		return null;
	}

	private UsefulCondition getUsefulCondition() {
		
		if (usefulCondition == null){
		
			String value = attrs.get(USEFUL_CONDITION);
			
			if (value.startsWith("TuplesCondition")){
				
				usefulCondition = new TuplesCondition();
				
			}
			
			if (value.startsWith("WorkLoadCondition")){
				
				ArrayList<String> params = extractParameters(value);
				
				String file = params.get(0);
				String description = params.get(1);
				usefulCondition = new WorkLoadCondition(file,description);

			}
			
		}
		
		return usefulCondition;
	}

	public Relation getRelation() {
		
		if (r == null){
			
			String value = attrs.get(RELATION);
			
			r = getStorageMediator().readRelation(new Long(value).longValue());
			
		}
		return r;
	}

	public StopPolicy getStopPolicy() {
		
		if (sp == null){
			
			String value = attrs.get(STOP_POLICY);
			
			if (value.startsWith("TTuplesExtracted")){
				
				ArrayList<String> params = extractParameters(value);
				
				String k = params.get(0);
				
				sp = new TTuplesExtracted(new Integer(k).intValue());
			}
			
		}
		
		return sp;
		
	}

	public StatisticsGenerator getStatisticsGenerator() {
		if (sg == null){
			
			String value = attrs.get(STATISTICS_GENERATOR);
			
			if (value.startsWith("TimeStatisticsPrinter")){
				
				sg = new TimeStatisticsPrinter();
			}
		}
		
		return sg;
	}

	public RankingGenerator getRankingGenerator() {

		if (rg == null){
			
			String value = attrs.get(RANKING_GENERATOR);
			
			if (value.startsWith("UsefulDocumentsSelector")){
				
				rg = new UsefulDocumentsSelector(getNumberOfDocumentCalculator());
			}
			if (value.startsWith("MeanUsefulValue")){
				
				rg = new MeanUsefulValue(getNumberOfDocumentCalculator());
			}
		}
		
		return rg;
	}

	public DocumentEstimator getNumberOfDocumentCalculator() {
		if (dEst == null){
			
			String value = attrs.get(NUMBER_OF_DOCUMENTS_CALCULATOR);
			
			if (value.startsWith("GlossEstimator")){
				
				dEst = new GlossEstimator();
			}
		}
		
		return dEst;
	}

	public MediatorInterface getStorageMediator() {
		
		if (mi == null){
			
			String value = attrs.get(MEDIATOR_INTERFACE);
			
			if (value.startsWith("MySQLMediator")){
				
				mi = new MySQLMediator();
			}
		}
		
		return mi;
	}

	public ArrayList<DataBase> getDatabases() {
		
		if (databases == null){
			
			String value = attrs.get(DATABASES);
			
			String[] dbs = value.split(",");
			
			long[] databs = new long[dbs.length];
			
			for (int i = 0; i < dbs.length; i++) {

				databs[i] = new Long(dbs[i]).intValue();
					
			}
			
			databases = getStorageMediator().readDatabases(databs);
			
		}
		
		return databases;
	}

	public ArrayList<Query> getQueries() {
		
		if (queries == null){
			
			String value = attrs.get(QUERIES);
			
			String[] qs = value.split(",");
			
			long[] qss = new long[qs.length];
			
			for (int i = 0; i < qs.length; i++) {

				qss[i] = new Long(qs[i]).longValue();

			}
			
			queries = getStorageMediator().readQueries(qss);
			
		}
		
		return queries;
	}

	public Integer getExperimentId() {

		if (e_id == null){
			
			
			
			e_id = new Integer(attrs.get(EXPERIMENT_ID));
			
		}

		return e_id;
	}

	public String getEnvironment() {
		
		if (env == null){
			
			env = attrs.get(ENVIRONMENT_CONFIGURATION);
			
		}
		
		return env;
		
	}

}
